Manim Community 学习笔记

Posted by 3nit on 2024-01-26

Catalog


Python

(还不太会)
https://www.runoob.com/python3/python3-basic-syntax.html

  • 推导式
  • 迭代器、生成器
  • 函数传参
  • 数据结构
  • 模块、包
  • 异常

Manim

Mobject

Vectorized Mobject

vector graphics

Mobject 显示

原点为屏幕中心

add(), remove()
shift(), move_to(), next_to(), align_to()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from manim import *

class MobjectPlacement(Scene):
def construct(self):
circle = Circle()
square = Square()
triangle = Triangle()

# place the circle two units left from the origin
circle.move_to(LEFT * 2)
# place the square to the left of the circle
square.next_to(circle, LEFT)
# align the left border of the triangle to the left border of the circle
triangle.align_to(circle, LEFT)

self.add(circle, square, triangle)
self.wait(1)

The move_to() method uses absolute units (measured relative to the ORIGIN),
while next_to() uses relative units (measured from the mobject passed as the first argument).
align_to() uses LEFT not as measuring units but as a way to determine the border to use for alignment. The coordinates of the borders of a mobject are determined using an imaginary bounding box around it.

Many methods in manim can be chained together. Technically, this is possible because most methods calls return the modified mobject.
right_square = Square(color=GREEN, fill_opacity=0.7).shift(2 * RIGHT).shift(UP)

Mobject 风格

1
2
3
4
5
circle.set_stroke(color=GREEN, width=20)
square.set_fill(YELLOW, opacity=1.0)
triangle.set_fill(PINK, opacity=0.5)

right_square = Square(color=GREEN, fill_opacity=0.7)

Only instances of VMobject implement set_stroke() and set_fill(). Instances of Mobject implement set_color() instead. The vast majority of pre-defined classes are derived from VMobject so it is usually safe to assume that you have access to set_stroke() and set_fill().

Mobject 顺序

1
2
self.add(triangle, square, circle)
#靠前的参数在下层

动画

动画类
1
2
3
4
5
6
7
8
# some animations display mobjects, ...
self.play(FadeIn(square))

# ... some move or rotate mobjects around...
self.play(Rotate(square, PI/4))

# some animations remove mobjects from the screen
self.play(FadeOut(square))
.animate 函数
1
2
3
4
5
6
# animate the change of color
self.play(square.animate.set_fill(WHITE))
self.wait(1)

# animate the change of position and the rotation at the same time
self.play(square.animate.shift(UP).rotate(PI / 3))

animate() is a property of all mobjects that animates the methods that come afterward.

动画持续时间
1
self.play(square.animate.shift(UP), run_time=3)

By default, any animation passed to play() lasts for exactly one second.

自定义动画(不会)

References: Animation DecimalNumber interpolate_mobject() play()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from manim import *

class Count(Animation):
def __init__(self, number: DecimalNumber, start: float, end: float, **kwargs) -> None:
# Pass number as the mobject of the animation
super().__init__(number, **kwargs)
# Set start and end
self.start = start
self.end = end

def interpolate_mobject(self, alpha: float) -> None:
# Set value of DecimalNumber according to alpha
value = self.start + (alpha * (self.end - self.start))
self.mobject.set_value(value)

class CountingScene(Scene):
def construct(self):
# Create Decimal Number and add it to scene
number = DecimalNumber().set_color(WHITE).scale(5)
# Add an updater to keep the DecimalNumber centered as its value changes
number.add_updater(lambda number: number.move_to(ORIGIN))

self.add(number)

self.wait()

# Play the Count Animation to count from 0 to 100 in 4 seconds
self.play(Count(number, 0, 100), run_time=4, rate_func=linear)

self.wait()

坐标

get_center() , get_top() and get_start()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from manim import *

class MobjectExample(Scene):
def construct(self):
p1= [-1,-1,0]
p2= [1,-1,0]
p3= [1,1,0]
p4= [-1,1,0]
a = Line(p1,p2).append_points(Line(p2,p3).points).append_points(Line(p3,p4).points)
point_start= a.get_start()
point_end = a.get_end()
point_center = a.get_center()
self.add(Text(f"a.get_start() = {np.round(point_start,2).tolist()}", font_size=24).to_edge(UR).set_color(YELLOW))
self.add(Text(f"a.get_end() = {np.round(point_end,2).tolist()}", font_size=24).next_to(self.mobjects[-1],DOWN).set_color(RED))
self.add(Text(f"a.get_center() = {np.round(point_center,2).tolist()}", font_size=24).next_to(self.mobjects[-1],DOWN).set_color(BLUE))

self.add(Dot(a.get_start()).set_color(YELLOW).scale(2))
self.add(Dot(a.get_end()).set_color(RED).scale(2))
self.add(Dot(a.get_top()).set_color(GREEN_A).scale(2))
self.add(Dot(a.get_bottom()).set_color(GREEN_D).scale(2))
self.add(Dot(a.get_center()).set_color(BLUE).scale(2))

self.add(Dot(a.point_from_proportion(0.5)).set_color(ORANGE).scale(2))

self.add(*[Dot(x) for x in a.points])

self.add(a)

形状转换
1
2
3
4
5
6
7
8
9
10
from manim import *

class ExampleTransform(Scene):
def construct(self):
self.camera.background_color = WHITE
#背景色
m1 = Square().set_color(RED)
m2 = Rectangle().set_color(RED).rotate(0.2)

self.play(Transform(m1,m2))

The Transform function maps points of the previous mobject to the points of the next mobject. This might result in strange behaviour, e.g. when the dots of one mobject are arranged clockwise and the other points are arranged counterclockwise. Here it might help to use the flip function and reposition the points via the roll function of numpy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from manim import *

class ExampleRotation(Scene):
def construct(self):
self.camera.background_color = WHITE
m1a = Square().set_color(RED).shift(LEFT)
m1b = Circle().set_color(RED).shift(LEFT)
m2a= Square().set_color(BLUE).shift(RIGHT)
m2b= Circle().set_color(BLUE).shift(RIGHT)

points = m2a.points
points = np.roll(points, int(len(points)/4), axis=0)
m2a.points = points

self.play(Transform(m1a,m1b),Transform(m2a,m2b), run_time=1)

Config

单文件全局配置

The most direct way of configuring Manim is through the global config object, which is an instance of ManimConfig. Each property of this class is a config option that can be accessed either with standard attribute syntax or with dict-like syntax:

1
2
3
from manim import *
config.background_color = WHITE #preferred
config["background_color"] = WHITE

Folder-wide config file

通过 manim.cfg 配置
To use a local configuration file when rendering your scene, you must create a file with the name manim.cfg in the same directory as your scene code.

1
2
3
4
5
[CLI]
# my config file
output_file = myscene
save_as_gif = True
background_color = WHITE

Starting with [CLI]

The names of the configuration options admissible in config files are exactly the same as the long names of the corresponding command- line flags. For example, the -c and --background_color flags are interchangeable, but the config file only accepts background_color as an admissible option.

User-wide config file

:通过 manim.cfg 配置
The user-wide config file lives in a special folder, depending on the operating system.

  • Windows: UserDirectory/AppData/Roaming/Manim/manim.cfg
  • MacOS: UserDirectory/.config/manim/manim.cfg
  • Linux: UserDirectory/.config/manim/manim.cfg

Manim will read both files, but if they are incompatible, the folder-wide file takes precedence.

CLI

Config 优先级

To summarize, the order of precedence for configuration options, from lowest to highest precedence is:

  1. Library-wide config file,

  2. user-wide config file, if it exists,

  3. folder-wide config file, if it exists OR custom config file, if passed via --config_file,

  4. other CLI flags, and

  5. any programmatic changes made after the config system is set.